﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using Cinchoo.Core;

namespace ChoWorkflowServer.Model
{
    public enum ChoTaskActionType { StartTask, StopTask, AbortTask, ActivateTask, InactivateTask, ResumeTask };
    public enum ChoTaskChangeType { Refresh, Add, Update, Remove };

    [Serializable]
    public abstract class ChoCommand
    {
    }

    [Serializable]
    public class ChoTaskActionCommand : ChoCommand
    {
        public ChoTaskActionType CommandType;
        public int BatchId;
        public string TaskName;
        public string WFName;
        public string CommandParameters;
        public string ScheduleName;
        public int Timeout;
        public int SleepBetweenRetry;
        public int MaxNoOfRetry;
        public bool RunDependentTasks;

        public string UniqueName
        {
            get { return "{0}_{1}".FormatString(TaskName, BatchId); }
        }
    }

    [Serializable]
    public class ChoTaskMgmtCommand : ChoCommand
    {
        public ChoTaskChangeType TaskMgmtType;
        public int TaskId;
        public int TaskGroupId;
        public string TaskName;
        public string WorkflowName;
        public string ScheduleName;
        public string TaskGroupName;
    }

    [Serializable]
    public class ChoTaskFeedbackStatusCommand : ChoCommand
    {
        public int BatchId;
        public string TaskName;
        public string ScheduleName;
        public int Status;
        public string CmdParameters;
        public string LogMsg;
        public DateTime ProcessStart;
        public DateTime? ProcessEnd;
        public TimeSpan? Duration;
        public DateTime? NextRunTime;
        public int ExitCode;
        public int? RetryCount;
        public string ModifiedBy;
    }

    [Serializable]
    public class ChoCalendarCommand : ChoCommand
    {
        public string CalendarName;
        public ChoTaskChangeType OperationType;
    }

    [Serializable]
    public class ChoMachinesCommand : ChoCommand
    {
        public KeyValuePair<string, string>[] Machines;
    }

    [Serializable]
    public class ChoWFListCommand : ChoCommand
    {
        public List<string> WFNames;
    }

    [Serializable]
    public class ChoClientCtrlCommand : ChoCommand
    {
        public bool MaxNoOfAllowedTasksReached;
    }

    public enum ChoSubscriberType { Client, Server }

    [Serializable]
    public class ChoSubscribeCommand : ChoCommand
    {
        public string HostName;
        public string IPAddress;
        public string ClusterName;
        public bool IsPrivateNode;
        public ChoSubscriberType SubscriberType;
    }

    [Serializable]
    public class ChoUsersACLChangedCommand : ChoCommand
    {
    }

    public interface IChoNoTrackingCommand
    {

    }

    [Serializable]
    public class ChoPingCommand : ChoCommand, IChoNoTrackingCommand
    {
    }

    [Serializable]
    public class ChoWFPlugInsChangedCommand : ChoCommand, IChoNoTrackingCommand
    {
    }

    [Serializable]
    public class ChoWFDefsChangedCommand : ChoCommand, IChoNoTrackingCommand
    {
    }

    [Serializable]
    public class ChoWFDataChangedCommand : ChoCommand, IChoNoTrackingCommand
    {
    }

    [Serializable]
    public class ChoCommandMessage : ChoCommand, ICloneable<ChoCommandMessage>
    {
        public static readonly ChoCommandMessage Default = new ChoCommandMessage() { TimeStamp = DateTime.MinValue };
        public static readonly ChoCommandMessage DefaultPingMsg = new ChoCommandMessage() { TimeStamp = DateTime.MinValue, Command = new ChoPingCommand() };
        public static readonly ChoCommandMessage DefaultWFPlugInsChangedMsg = new ChoCommandMessage() { TimeStamp = DateTime.MinValue, Command = new ChoWFPlugInsChangedCommand() };
        public static readonly ChoCommandMessage DefaultWFDefsChangedMsg = new ChoCommandMessage() { TimeStamp = DateTime.MinValue, Command = new ChoWFDefsChangedCommand() };
        public static readonly ChoCommandMessage DefaultWFDataChangedMsg = new ChoCommandMessage() { TimeStamp = DateTime.MinValue, Command = new ChoWFDataChangedCommand() };

        private const string UniversalHostName = "<ALL>";

        [XmlElement("command", typeof(ChoCommand))]
        public ChoCommand Command;

        public DateTime TimeStamp;
        public string Tag;
        public string HostName;
        public string OriginHostName;
        public string User;

        public static ChoCommandMessage New(string originHostName = null, string userName = null)
        {
            ChoCommandMessage commandMessage = new ChoCommandMessage();
            commandMessage.TimeStamp = DateTime.Now;

            if (originHostName.IsNullOrWhiteSpace())
                commandMessage.OriginHostName = commandMessage.HostName = Environment.MachineName;
            else
                commandMessage.OriginHostName = commandMessage.HostName = originHostName;

            commandMessage.User = userName == null ? ChoUser.CurrentUser : userName;

            return commandMessage;
        }

        public T GetCommand<T>()
            where T : ChoCommand
        {
            return (T)Command;
        }

        public bool IsUniversalMessage
        {
            get
            {
                return HostName == UniversalHostName;
            }
        }

        public bool IsLoopbackMessage
        {
            get
            {
                return OriginHostName == Environment.MachineName;
            }
        }

        public void Universalize()
        {
            HostName = UniversalHostName;
        }

        public ChoCommandMessage Clone()
        {
            ChoCommandMessage commandMessage = new ChoCommandMessage();
            commandMessage.TimeStamp = TimeStamp;
            commandMessage.HostName = HostName;
            commandMessage.User = User;

            commandMessage.Command = Command;

            return commandMessage;
        }

        object ICloneable.Clone()
        {
            return Clone();
        }
    }

    [Serializable]
    public class ChoServerMsgCommand : ChoCommand
    {
        public int ErrorCode { get; set; }
        public string Message { get; set; }
        public Severity Severity { get; set; }
        public string Detail { get; set; }
    }
}
